package cn.memset.code.stream;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.stream.IntStream;
import java.util.stream.Stream;

public class BasicExample {
    public static void main(String[] args) {
        intermediateStatefulOperations();
    }

    public static void simpleStream() {
        List<String> words = Arrays.asList("hello", "world", "I", "love", "you");
        int letterCount = words.stream()
                .filter(s -> s.length() > 3)  // 过滤掉长度小于等于3的单词
                .mapToInt(String::length)     // 将每个单词映射为单词长度
                .sum();  // 计算总长度 5(hello) + 5(world) + 4(love) = 14

        // 输出为 14
        System.out.println(letterCount);
    }

    public static void intermediateOperations() {
        List<String> words = Arrays.asList("hello", "world", "I", "love", "you");

        System.out.println("start: " + System.currentTimeMillis());

        Stream<String> interStream = words.stream()
                .filter(s -> {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // do nothing
                    }
                    return s.length() > 3;
                });
        IntStream intStream = interStream.mapToInt(s -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // do nothing
            }
            return s.length();
        });

        // 因为 filter 和 map 操作都属于中间操作，并不会真正执行，
        // 所以它们不受 Thread.sleep 的影响，耗时很短
        System.out.println("after filter && map: " + System.currentTimeMillis());

        int letterCount = intStream.sum();

        // sum 属于终止操作，会执行之前定义的中间操作，
        // Thread.sleep 被真正执行了，耗时为 5(filter) + 3(mapToInt) = 8秒
        System.out.println("after sum: " + System.currentTimeMillis());

        // 输出为 14
        System.out.println(letterCount);
    }

    public static void filterStream() {
        List<String> words = Arrays.asList("hello", "world", "I", "love", "you");
        words.stream()
                .filter(s -> s.length() > 3)  // 过滤掉长度小于等于3的单词
                .forEach(s -> System.out.println(s));
    }

    public static void limitStream() {
        Random random = new Random();

        // 打印左闭右开区间中 [1, 100) 中的 5 个随机整数
        random.ints(1, 100)
                .limit(5)
                .forEach(System.out::println);
    }

    public static void distinctStream() {
        Random random = new Random();

        // 在左闭右开区间中 [1, 100) 随机生成 10 个不重复的数字
        random.ints(1, 100)
                .distinct()
                .limit(10)
                .forEach(System.out::println);

        /*
        // 一个有趣的问题，如果 limit 方法放在 distinct 方法前面，结果和上面的代码有什么区别吗？
        random.ints(1, 100)
                .limit(10)
                .distinct()
                .forEach(System.out::println);
        */
    }

    public static void sortedStream() {
        List<String> list = Arrays.asList("Guangdong", "Fujian", "Hunan", "Guangxi");

        // 自然排序
        list.stream().sorted().forEach(System.out::println);

        System.out.println("===============");

        // 对省份进行排序，首先按照长度排序，如果长度一样，则按照字母顺序排序
        list.stream().sorted((first, second) -> {
            int lenDiff = first.length() - second.length();
            return lenDiff == 0 ? first.compareTo(second) : lenDiff;
        }).forEach(System.out::println);
    }

    public static void intermediateStatefulOperations() {
        List<String> words = Arrays.asList("hello", "world", "I", "love", "you");

        System.out.println("start: " + System.currentTimeMillis());

        Stream<String> stream = words.stream();
        stream = stream.filter(s -> {
            System.out.println("filter: " + s);
            return s.length() > 3;
        });
        System.out.println("after filtr: " + System.currentTimeMillis());

        // 如果注释掉sorted操作，会观察到一些有意思的现象
        stream = stream.sorted((s1, s2) -> {
            System.out.println("compare: " + s1 + ", " + s2);
            return s1.compareTo(s2);
        });
        System.out.println("after sorted: " + System.currentTimeMillis());

        IntStream intStream = stream.mapToInt(s -> {
            System.out.println("map to int: " + s);
            return s.length();
        });
        System.out.println("after mapToInt: " + System.currentTimeMillis());

        intStream.sum();
        System.out.println("after sum: " + System.currentTimeMillis());
    }
}
